"""
2018-6-23 by Stone
1.Derivatives class

2018-6-28 to 29 by Stone
1.Link list structure -- class Node

"""


class Derivatives:
    def __init__(self, dt):
        self.__old = 0
        self.__new = 0
        self.__dt  = dt

    def update(self, new):
        self.__old = self.__new
        self.__new = new
        d = (self.__new - self.__old) / self.__dt
        print 'd,o,n',d,self.__old, self.__new
        return d


class Node:
    """Linked list node. It is specially designed for simulator use, which is used to contain the car."""

    def __init__(self):
        self._data = None
        self._previous = None
        self._next     = None

    def __repr__(self):
        return "<linked list node>; data: %s" % self._data

    def get_data(self):
        return self._data

    def get_next(self):
        return self._next

    def get_previous(self):
        return self._previous

    def set_data(self, data):
        self._data = data

    def set_next(self, node):
        self._next = node

    def set_previous(self, node):
        self._previous = node


class LinkedList:
    def __init__(self):
        self._head = None
        self._end  = None
        self.__len = 0

    def __iter__(self):
        n = self._head
        while True:
            yield n
            n = n.get_next()
            if n is None:
                raise StopIteration

    def append(self, data):
        self.__len += 1

        n = Node()
        n.set_data(data)
        if self._head is None:
            self._head = n
            self._end  = n
        else:
            self._end.set_next(n)
            n.set_previous(self._end)
            self._end = n

    def insert(self, node, data):
        """insert obj after id_ node, before one next to id_ node.
        Bug: It does not check if the node in this linked list or not.
        """
        self.__len += 1

        n = Node()
        n.set_data(data)
        prev_n = node
        next_n = prev_n.get_next()

        n.set_previous(prev_n)
        n.set_next(next_n)
        prev_n.set_next(n)
        next_n.set_previous(n)

    def delete(self, node):
        self.__len -= 1

        prev_n = node.get_previous()
        next_n = node.get_next()
        prev_n.set_next(next_n)
        next_n.set_previous(prev_n)

        del node


# ===== test =====
def test():
    global l, n
    l = LinkedList()

    print '\nl.append() '
    for i in range(10):
        l.append(i)
    print l

    try:
        print '\nget_next()'
        for n in l:
            print n, n.get_data()
    finally: pass

    print '\n delete, insert'
    i = 0
    for j in l:
        i+= 1
        if i == 5:
            l.delete(j)
            break

    l.insert(j.get_next(), 100)
    print 'j: ',j
    for i in l:
        print i


if __name__ == '__main__':
    test()
